﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Pop
{
    class Ball:Object
    {
        int initialVelocity = 7;
        int maxVelocity = 12;
        int ballStrength = 1;
        float velocityLength; 
        float increaseVelocityFactor = 0.1F;
        Random random = new Random();
        SoundEffect soundEffect;
        public enum BallCollision { NORMAL, LIFETAKING };

        #region "Constructors"

        public Ball(GameWindow window, Texture2D texture, Vector2 position, SoundEffect soundEffect)
            : base(texture, position)
        {
            this.velocityLength = initialVelocity;
            this.soundEffect = soundEffect;
            this.size = texture.Bounds;
            reset(window);
        }

        public Ball(GameWindow window, Texture2D texture, Vector2 position, SoundEffect soundEffect,int initialVelocity,int maxVelocity)
            : base(texture, position)
        {
            this.initialVelocity = initialVelocity;
            this.maxVelocity = maxVelocity;
            this.velocityLength = initialVelocity;
            this.soundEffect = soundEffect;
            this.size = texture.Bounds;            
            reset(window);
        }

        public Ball(GameWindow window, Texture2D texture, Vector2 position, SoundEffect soundEffect, int ballStrength)
            : base(texture, position)
        {
            this.ballStrength = ballStrength;
            this.velocityLength = initialVelocity;
            this.soundEffect = soundEffect;
            this.size = texture.Bounds;
            reset(window);
        }

        public Ball(GameWindow window, Texture2D texture, Vector2 position, SoundEffect soundEffect,int initialVelocity,int maxVelocity, int ballStrength)
            : base(texture, position)
        {
            this.ballStrength = ballStrength;
            this.initialVelocity = initialVelocity;
            this.maxVelocity = maxVelocity;
            this.velocityLength = initialVelocity;
            this.soundEffect = soundEffect;
            this.size = texture.Bounds;
            reset(window);
        }



        # endregion

       
        private float VelocityY
        {
            get { return velocity.Y; }
            set 
            { 
                velocity.Y = value;
                if (velocity.X < 0) { velocity.X = -(float)Math.Sqrt(Math.Abs(velocityLength * velocityLength - (velocity.Y * velocity.Y))); }
                else { velocity.X = (float)Math.Sqrt(Math.Abs(velocityLength*velocityLength  - (velocity.Y * velocity.Y))); }     
            }

        }
        private float VelocityX
        {
            get { return velocity.X; }
            set
            {
                velocity.X = value;
                if (velocity.Y < 0) { velocity.Y = -(float)Math.Sqrt(Math.Abs(velocityLength * velocityLength - (velocity.X * velocity.X))); }
                else { velocity.Y = (float)Math.Sqrt(Math.Abs(velocityLength * velocityLength - (velocity.X * velocity.X))); }
                //Math.Pow(maxVelocity, 2);
            }

        }

        private void increaseVelocityLength()
        {
            if (velocityLength + increaseVelocityFactor > maxVelocity)
            {
                velocityLength = maxVelocity;
            }
            else
            {
                velocityLength += increaseVelocityFactor;
            }

        }

        public BallCollision Update (GameWindow window)
        {
                  position+=velocity;
                  size.X = (int)position.X;
                  size.Y = (int)position.Y;     
                  return WindowCollision(window);          
        }

        public void reset(GameWindow window)
        {
            this.position = new Vector2(
                window.ClientBounds.Width / 2
                - this.size.Width / 2,
                window.ClientBounds.Height / 2
                - this.size.Height / 2);//AQUI

            velocityLength = initialVelocity;

            float randomX = (float)(random.NextDouble() * (velocityLength - 2)) + 2;
            VelocityX = randomX;
            if (random.NextDouble() > 0.5) { VelocityX = -VelocityX; }
            if (random.NextDouble() > 0.5) { VelocityY = -VelocityY; }
        }


        public override void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, position, Color.White);           
        }

        public void Draw(SpriteBatch spriteBatch, SpriteFont font)
        {
            spriteBatch.Draw(texture, position, Color.White);
            spriteBatch.DrawString(font, velocityLength.ToString(), Vector2.Zero, Color.White);
            spriteBatch.DrawString(font, "( " + velocity.X + " | " + velocity.Y + " )", new Vector2(0,font.MeasureString("0").Y), Color.White);
        }

        #region Colision

        public void PalletCollisionLinesSegment(Pallet pallet)
        {
            if ((!(pallet is Block) || (((Block)pallet).Enabled)))
            {
                BoundingSphere bSphere = new BoundingSphere(new Vector3((int)(this.position.X + 0.5 * size.Width), (int)(this.position.Y + 0.5 * size.Height), 0), (this.size.Width * 0.5F));
                Vector3 vect3 = new Vector3((int)pallet.Position.X, (int)pallet.Position.Y, 0);
                BoundingBox rectP = new BoundingBox(vect3, new Vector3(vect3.X + pallet.Size.Width, vect3.Y + pallet.Size.Height, vect3.Z));
                
                if (bSphere.Intersects(rectP))
                {
                    //vetores representativos dos vértices da palheta
                    Vector2 palA = pallet.Position;
                    Vector2 palB = new Vector2(pallet.Position.X + pallet.Size.Width, pallet.Position.Y);
                    Vector2 palC = new Vector2(pallet.Position.X + pallet.Size.Width, pallet.Position.Y + pallet.Size.Height);
                    Vector2 palD = new Vector2(pallet.Position.X, pallet.Position.Y + pallet.Size.Height);
                    
                    //vetores representativos dos vértices da bola antes de aplicada a velocidade
                    Vector2 bAntesA = position;
                    Vector2 bAntesB = new Vector2(position.X + size.Width, position.Y);
                    Vector2 bAntesC = new Vector2(position.X + size.Width, position.Y + size.Height);
                    Vector2 bAntesD = new Vector2(position.X , position.Y + size.Height);

                    //vetores representativos dos vértices da bola após ser aplicada a velocidade
                    Vector2 bDepoisA = bAntesA + velocity;
                    Vector2 bDepoisB = bAntesB + velocity;
                    Vector2 bDepoisC = bAntesC + velocity;
                    Vector2 bDepoisD = bAntesD + velocity;
                    
                    //ponto onde ocorre o cruzamento de retas
                    Vector2 ptI = new Vector2(Position.X + velocity.X, Position.Y + velocity.Y); //ponto de interseção

                    bool crossed = false;

                    increaseVelocityLength();
                    soundEffect.Play();

                    if (pallet is Block)
                    {
                        ((Block)pallet).NumberOfHitsToBreak -= 1;
                        ((Block)pallet).SoundEffect.Play();
                    }

                    if (velocity.Y > 0)//bola vem de cima para baixo
                    {

                        if (velocity.X > 0) //bola vem da esq para a dir ==================================================================================
                        {
                            if (Geometry.InterSegReta( bAntesB,
                                                      bDepoisD, 
                                                      palA, 
                                                      new Vector2(palB.X + (pallet.Size.Width * 0.1F),palB.Y),
                                                      ref ptI))
                            { //colisão no topo
                                this.position = new Vector2(Position.X + velocity.X,pallet.Position.Y - Size.Height);//new Vector2(ptI.X, ptI.Y -Size.Height);
                                this.VelocityY = -this.VelocityY;
                                crossed = true;
                            }
                            else if (Geometry.InterSegReta(bAntesD,
                                                           bDepoisB,  
                                                           palA,
                                                           new Vector2(palD.X, palD.Y + (pallet.Size.Height * 0.1F)), 
                                                           ref ptI))
                            { //colisão na esquerda
                               
                                this.position = new Vector2(pallet.Position.X - Size.Width, Position.Y + velocity.Y);//new Vector2(ptI.X - Size.Width, ptI.Y);
                                this.VelocityX = -this.VelocityX;
                                crossed = true;
                            }
                        }

                        else //bola vem da dir para a esq ==================================================================================
                        {
                            if (Geometry.InterSegReta(bAntesA,
                                                      bDepoisC,
                                                      palA,
                                                      new Vector2(palB.X + (pallet.Size.Width * 0.1F), palB.Y), 
                                                      ref ptI))
                            { //colisão no topo
                                this.position = new Vector2(Position.X + velocity.X, pallet.Position.Y - Size.Height);//new Vector2(ptI.X, ptI.Y - Size.Height);
                                this.VelocityY = -this.VelocityY;
                                crossed = true;
                            }
                            else if (Geometry.InterSegReta(bAntesC,
                                                      bDepoisA,
                                                      palB,
                                                      new Vector2(palC.X, palC.Y + (pallet.Size.Height * 0.1F)),
                                                      ref ptI))
                            { //colisão na direita                               
                                this.position = new Vector2(pallet.Position.X+ pallet.Size.Width, Position.Y + velocity.Y);//ptI;
                                this.VelocityX = -this.VelocityX;
                                crossed = true;
                            }
                        }

                    }


                    else //bola vem de baixo para cima
                    {
                        if (velocity.X > 0) //bola vem da esq para a dir ==================================================================================
                        {
                            if (Geometry.InterSegReta(bAntesD,
                                                      bDepoisA,                                                      
                                                      palD,
                                                      new Vector2(palC.X + (pallet.Size.Width * 0.1F), palC.Y),
                                                      ref ptI))
                            { //colisão em baixo
                                this.position = new Vector2(Position.X + velocity.X, pallet.Position.Y + pallet.Size.Height); //ptI;
                                this.VelocityY = -this.VelocityY;
                                crossed = true;
                            }
                            else if (Geometry.InterSegReta(bAntesA,
                                                      bDepoisD,
                                                      palD,
                                                      new Vector2(palA.X, palA.Y - (pallet.Size.Height * 0.1F)),
                                                      ref ptI))
                            { //colisão na esquerda
                                this.position = new Vector2(pallet.Position.X - Size.Width, Position.Y + velocity.Y);
                                this.VelocityX = -this.VelocityX;
                                crossed = true;
                            }
                        }

                        else //bola vem da dir para a esq ==================================================================================
                        {
                            if (Geometry.InterSegReta(bAntesD,
                                                      bDepoisB,
                                                      palC,
                                                      new Vector2(palD.X - (pallet.Size.Width * 0.1F), palD.Y),
                                                      ref ptI))
                            { //colisão em baixo
                                this.position = new Vector2(Position.X + velocity.X, pallet.Position.Y + pallet.Size.Height); 
                                this.VelocityY = -this.VelocityY;
                                crossed = true;
                            }
                            else if (Geometry.InterSegReta(bAntesD,
                                                      bDepoisB,                                                      
                                                      palC,
                                                      new Vector2(palB.X, palB.Y - (pallet.Size.Height * 0.1F)),
                                                      ref ptI))
                            { //colisão na direita
                                this.position = new Vector2(pallet.Position.X + pallet.Size.Width, Position.Y + velocity.Y); 
                                this.VelocityX = -this.VelocityX;
                                crossed = true;
                            }
                        }

                    }

                    if (!crossed)
                    {
                        this.VelocityX = -this.VelocityX;
                        this.VelocityY = -this.VelocityY;
                        this.position = this.position - this.velocity;
                        //increaseHorizontalVelocity();
                    }

                }
            }
        }
       
        public BallCollision VerificaColisao(Pallet pallet)
        {
            if ((!(pallet is Block) || ( ((Block)pallet).Enabled)))
            {
            

                if ((position.X > pallet.Position.X - size.Width) & (position.X < pallet.Position.X + pallet.Size.Width) ){
                    if ((position.Y > pallet.Position.Y - size.Height) & (position.Y < pallet.Position.Y + pallet.Size.Height))
                    {
                        soundEffect.Play();
                        if (pallet is Block)
                        {
                            ((Block)pallet).Enabled = false;
                        }

                        if (velocity.Y > 0)
                        {
                            this.position.Y = pallet.Position.Y - this.size.Height;
                            //increaseHorizontalVelocity(true);
                        }
                        else
                        {
                            this.position.Y = pallet.Position.Y + pallet.Size.Height - this.size.Y;
                            //increaseHorizontalVelocity(false);
                        }
                        this.velocity.Y = -this.velocity.Y;

                        //palheta.debugAreadeImpacto = increaseVerticalVelocity(palheta);
                  
                    }
                }

            }

            return BallCollision.NORMAL;//palheta.debugAreadeImpacto;
            
        }

        public void Colisao(Pallet pallet)
        {
            int absoluteX, absoluteY;

            if (this.velocity.X >= 0)
                absoluteX = (int)this.velocity.X;
            else
                absoluteX = -(int)this.velocity.X;

            if (this.velocity.Y >= 0)
                absoluteY = (int)this.velocity.Y;
            else
                absoluteY = -(int)this.velocity.Y;

            if (!(pallet is Block) || (((Block)pallet).Enabled))
            {

                if (this.size.Intersects(pallet.Size))
                {
                    //Retângulo inferior
                    if (this.size.Intersects(new Rectangle(pallet.Size.Left, pallet.Size.Bottom - absoluteY + 1, pallet.Size.Width, absoluteY - 1)) && (this.velocity.Y > 0))
                    {
                        this.velocity.Y *= -1;
                        if (pallet is Block)
                            ((Block)pallet).Enabled = false;
                    }

                    //Retângulo superior
                    else if (this.size.Intersects(new Rectangle(pallet.Size.Left, pallet.Size.Top, pallet.Size.Width, absoluteY - 1)) && (this.velocity.Y < 0))
                    {
                        this.velocity.Y *= -1;
                        if (pallet is Block)
                            ((Block)pallet).Enabled = false;
                    }

                    //Retângulo esquerdo
                    else if (this.size.Intersects(new Rectangle(pallet.Size.Left, pallet.Size.Top, absoluteX - 1, pallet.Size.Height)) && (this.velocity.X > 0))
                    {
                        this.velocity.X *= -1;
                        if (pallet is Block)
                            ((Block)pallet).Enabled = false;
                    }

                    //Retângulo direito
                    else if (this.size.Intersects(new Rectangle(pallet.Size.Right - absoluteX + 1, pallet.Size.Top, absoluteX - 1, pallet.Size.Height)) && (this.velocity.X < 0))
                    {
                        this.velocity.X *= -1;
                        if (pallet is Block)
                            ((Block)pallet).Enabled = false;
                    }
                }
            }

        }

        public void Colisao2(Pallet pallet)
        {
            if (this.size.Intersects(pallet.Size))
            {

            }
        }

        private BallCollision WindowCollision(GameWindow window)
        {
            if (position.Y <= 0)
            {
                soundEffect.Play();
                position.Y = 0;
                VelocityY = -VelocityY;
                
            }

            if (position.Y >= window.ClientBounds.Height - size.Height)
            {
                //soundEffect.Play();
                position.Y = window.ClientBounds.Height - size.Height;
                VelocityY = -VelocityY;
                return BallCollision.LIFETAKING; 
            }

            if (position.X <= 0)
            {
                soundEffect.Play();
                position.X = 0;
                VelocityX = -VelocityX;
            }

            if (position.X >= window.ClientBounds.Width - size.Width)
            {
                soundEffect.Play();
                position.X = window.ClientBounds.Width - size.Width;
                VelocityX = -VelocityX;             
            }
            return BallCollision.NORMAL;
        }

        #endregion

        //private int increaseVerticalVelocity(Pallete palheta)
        //{
            
        //    double TamanhoAreaPalheta = palheta.Size.Height / 15;
        //    int AreaDeImpacto = (int)((position.Y - palheta.Position.Y) / TamanhoAreaPalheta);

        //    switch (AreaDeImpacto)
        //    {
        //        case 0:
        //            if (velocity.Y > -maxVelocity.Y) velocity.Y -= 3;
        //            break;
        //        case 1: case 2:
        //            if (velocity.Y > -maxVelocity.Y) velocity.Y -= 2;
        //            break;
        //        case 3: case 4: case 5:
        //            if (velocity.Y > -maxVelocity.Y) velocity.Y -= 1;
        //            break;
        //        case 6: case 7: case 8:
        //            break;
        //        case 9: case 10: case 11:
        //            if (velocity.Y < maxVelocity.Y) velocity.Y += 1;
        //            break;
        //        case 12: case 13:
        //            if (velocity.Y < maxVelocity.Y) velocity.Y += 2;
        //            break;
        //        case 14:                    
        //            if (velocity.Y < maxVelocity.Y) velocity.Y += 3;
        //            break;
        //    }
        //    return AreaDeImpacto;
        //}

   
    }

}
